Imports System.Runtime.InteropServices
Imports System
Imports System.Security
Imports System.Security.Permissions
Imports System.IO
Imports System.Windows.Forms
Imports System.Diagnostics

''' <devdoc>
'''     This class is intended to use with the C# 'using' statement in
'''     to activate an activation context for turning on visual theming at
'''     the beginning of a scope, and have it automatically deactivated
'''     when the scope is exited.
''' </devdoc>

<SuppressUnmanagedCodeSecurity()> _
Friend Class EnableTaskDialogInScope
    Implements IDisposable
    ' Private data
    Private cookie As UInteger
    Private Shared enableThemingActivationContext As ACTCTX
    Private Shared hActCtx As IntPtr
    Private Shared contextCreationSucceeded As Boolean = False

    Public Sub New(ByVal enable As Boolean)
        cookie = 0
        If enable Then
            If EnsureActivateContextCreated() Then
                If Not ActivateActCtx(hActCtx, cookie) Then
                    ' Be sure cookie always zero if activation failed
                    cookie = 0
                End If
            End If
        End If
    End Sub

    ' http://adventuresinwpf.blogspot.com/2008/09/which-version-of-dll-is-loaded.html
    Friend Shared Function GetLoadedModuleVersion(ByVal name As String) As FileVersionInfo
        Dim process As Process = Process.GetCurrentProcess()
        For Each [module] As ProcessModule In process.Modules
            If [module].ModuleName.ToLower() = name Then
                Return [module].FileVersionInfo
            End If
        Next
        Return Nothing
    End Function

    Public Shared Function HaveComctl6() As Boolean
        Dim verInfo As FileVersionInfo = GetLoadedModuleVersion("comctl32.dll")
        Return Not verInfo Is Nothing AndAlso verInfo.FileMajorPart >= 6
    End Function

    Protected Overrides Sub Finalize()
        Try

            Dispose(False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub

    Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
    End Sub

    Private Sub Dispose(ByVal disposing As Boolean)
        If cookie <> 0 Then
            If DeactivateActCtx(0, cookie) Then
                ' deactivation succeeded...
                cookie = 0
            End If
        End If
    End Sub

    Private ctxlock As New Object()

    Private Function EnsureActivateContextCreated() As Boolean
        SyncLock ctxlock
            If Not contextCreationSucceeded Then
                ' Pull manifest from the .NET Framework install
                ' directory

                Dim assemblyLoc As String = Nothing

                Dim fiop As New FileIOPermission(PermissionState.None)
                fiop.AllFiles = FileIOPermissionAccess.PathDiscovery
                fiop.Assert()
                Try
                    assemblyLoc = GetType([Object]).Assembly.Location
                Finally
                    CodeAccessPermission.RevertAssert()
                End Try

                Dim manifestLoc As String = Nothing
                Dim installDir As String = Nothing
                If assemblyLoc <> Nothing Then
                    installDir = Path.GetDirectoryName(assemblyLoc)
                    Const manifestName As String = "XPThemes.manifest"
                    manifestLoc = Path.Combine(installDir, manifestName)
                End If

                If manifestLoc <> Nothing AndAlso installDir <> Nothing Then
                    enableThemingActivationContext = New ACTCTX()
                    enableThemingActivationContext.cbSize = Marshal.SizeOf(GetType(ACTCTX))
                    enableThemingActivationContext.lpSource = manifestLoc

                    ' Set the lpAssemblyDirectory to the install
                    ' directory to prevent Win32 Side by Side from
                    ' looking for comctl32 in the application
                    ' directory, which could cause a bogus dll to be
                    ' placed there and open a security hole.
                    enableThemingActivationContext.lpAssemblyDirectory = installDir
                    enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID

                    ' Note this will fail gracefully if file specified
                    ' by manifestLoc doesn't exist.
                    hActCtx = CreateActCtx(enableThemingActivationContext)
                    contextCreationSucceeded = (hActCtx <> New IntPtr(-1))
                End If
            End If

            ' If we return false, we'll try again on the next call into
            ' EnsureActivateContextCreated(), which is fine.
            Return contextCreationSucceeded
        End SyncLock
    End Function

    ' All the pinvoke goo...
    <DllImport("Kernel32.dll")> _
    Private Shared Function CreateActCtx(ByRef actctx As ACTCTX) As IntPtr
    End Function
    <DllImport("Kernel32.dll")> _
    Private Shared Function ActivateActCtx(ByVal hActCtx As IntPtr, ByRef lpCookie As UInteger) As Boolean
    End Function
    <DllImport("Kernel32.dll")> _
    Private Shared Function DeactivateActCtx(ByVal dwFlags As UInteger, ByVal lpCookie As UInteger) As Boolean
    End Function

    Private Const ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID As Integer = &H4

    Private Structure ACTCTX
        Public cbSize As Integer
        Public dwFlags As UInteger
        Public lpSource As String
        Public wProcessorArchitecture As UShort
        Public wLangId As UShort
        Public lpAssemblyDirectory As String
        Public lpResourceName As String
        Public lpApplicationName As String
    End Structure
End Class
